package com.supreme.cacheserver.controller;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.supreme.cacheserver.service.BatchTestService;
import com.supreme.cacheserver.service.TestService;
import com.supreme.commonboot.utils.AjaxResp;
import com.supreme.commonentity.mysql.primary.MBTest;
import com.supreme.commonmybatis.mapper.TestMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping(value = "test")
public class TestController {

    @Resource
    private TestMapper testMapper;

    @Resource
    private TestService testService;

    @Resource
    private BatchTestService batchTestService;

    @Resource
    private RedisTemplate<String, Serializable> redisTemplate;

    @Resource
    private DruidDataSource druidDataSource;

    @Resource
    private HttpServletRequest httpServletRequest;

    @GetMapping(value = "hello")
    public AjaxResp helloTest() {
        return AjaxResp.instance("hello");
    }

    @GetMapping(value = "from/study-server")
    public AjaxResp fromStudyServer() {
        String transMethod = httpServletRequest.getHeader("trans-method");
        return AjaxResp.instance(transMethod);
    }

    @GetMapping(value = "fileBeat/{level}")
    public AjaxResp fileBeat(@PathVariable(value = "level") Integer level) {
        String randomAlphabetic = RandomStringUtils.randomAlphabetic(16);
        switch (level) {
            case -1:
                int exp = 1 / 0;
                System.out.println("exp = " + exp);
                break;

            case 0:
                log.debug(randomAlphabetic);
                log.info(randomAlphabetic);
                log.warn(randomAlphabetic);
                log.error(randomAlphabetic);
                break;

            case 1:
                log.debug(randomAlphabetic);
                break;

            case 2:
                log.info(randomAlphabetic);
                break;

            case 3:
                log.warn(randomAlphabetic);
                break;

            case 4:
                log.error(randomAlphabetic);
                break;
        }

        return AjaxResp.instance(randomAlphabetic);
    }

    @GetMapping(value = "dataSource")
    public AjaxResp dataSource() {
        int maxActive = druidDataSource.getMaxActive();
        System.out.println("maxActive = " + maxActive);
        return AjaxResp.instance();
    }

    @GetMapping(value = "tests")
    public AjaxResp selectList() {
        List<MBTest> selectList = testMapper.selectList(Wrappers.emptyWrapper());
        return new AjaxResp(selectList);
    }

    @PostMapping(value = "create")
    public AjaxResp createTest(@RequestBody MBTest test) {
        int insert = this.testMapper.insert(test);
        return new AjaxResp(insert);
    }

    @PostMapping(value = "update")
    public AjaxResp updateTest(@RequestBody MBTest test) {
        int update = this.testMapper.updateById(test);
        return new AjaxResp(update);
    }

    @PostMapping(value = "syncToRedis/{redisKey}")
    public AjaxResp syncToRedis(@PathVariable(value = "redisKey") String key) {
        List<MBTest> selectList = testMapper.selectList(Wrappers.emptyWrapper());
        redisTemplate.opsForValue().set(key, (Serializable) selectList);
        return AjaxResp.instance();
    }

    @PostMapping(value = "syncToRedisList/{redisKey}")
    public AjaxResp syncToRedisList(@PathVariable(value = "redisKey") String key) {
        List<MBTest> selectList = testMapper.selectList(Wrappers.emptyWrapper());
        MBTest[] testArray = selectList.toArray(new MBTest[0]);
        redisTemplate.opsForList().rightPushAll(key, testArray);
        return AjaxResp.instance();
    }

    @PostMapping(value = "syncToRedisHash/{redisKey}")
    public AjaxResp syncToRedisHash(@PathVariable(value = "redisKey") String key) {
        List<MBTest> selectList = testMapper.selectList(Wrappers.emptyWrapper());
        Map<String, MBTest> testMap = selectList.stream()
                .collect(Collectors.toMap(mbTest -> String.valueOf(mbTest.getId()), Function.identity()));
        redisTemplate.opsForHash().putAll(key, testMap);
        return AjaxResp.instance();
    }

    @PostMapping(value = "syncToRedisSet/{redisKey}")
    public AjaxResp syncToRedisSet(@PathVariable(value = "redisKey") String key) {
        List<MBTest> selectList = testMapper.selectList(Wrappers.emptyWrapper());
        MBTest[] testArray = selectList.toArray(new MBTest[0]);
        redisTemplate.opsForSet().add(key, testArray);
        return AjaxResp.instance();
    }

    @PostMapping(value = "syncToRedisZSet/{redisKey}")
    public AjaxResp syncToRedisZSet(@PathVariable(value = "redisKey") String key) {
        List<MBTest> selectList = testMapper.selectList(Wrappers.emptyWrapper());
        AtomicLong zSetIndex = new AtomicLong();
        final Set<ZSetOperations.TypedTuple<Serializable>> collect = selectList.stream()
                .map((Function<MBTest, ZSetOperations.TypedTuple<Serializable>>) mbTest -> {
                    zSetIndex.getAndIncrement();
                    return new DefaultTypedTuple<>(mbTest, zSetIndex.doubleValue());
                }).collect(Collectors.toSet());
        redisTemplate.opsForZSet().add(key, collect);
        return AjaxResp.instance();
    }

    @PostMapping(value = "insertTestListToRedis/{redisKey}")
    public AjaxResp insertTestListToRedis(@PathVariable(value = "redisKey") String key, @RequestBody List<MBTest> testList) {
        testService.insertTestListToRedis(key, testList);
        return AjaxResp.instance();
    }

    @GetMapping(value = "getTestListFromRedis/{redisKey}")
    public AjaxResp getTestListFromRedis(@PathVariable(value = "redisKey") String key) {
        List<MBTest> testList = testService.getTestListFromRedis(key);
        return AjaxResp.instance(testList);
    }

    @PostMapping(value = "insertTestForTransaction/{duration}")
    public AjaxResp insertTestForTransaction(@PathVariable(value = "duration") Long duration) {
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        for (int i = 0; i < 100; i++) {
            CompletableFuture.runAsync(() ->
                    batchTestService.insertTestForTransaction(duration), executorService);
        }
        return AjaxResp.instance();
    }
}
